package jt

import (
	"encoding/binary"
	"errors"
	"fmt"
	"time"

	"github.com/dontls/xproto"
)

// var pTypes = [128]string{
// 	"G.721",
// 	"G.822",
// 	"G.721",
// 	"G.722",
// 	"G.723",
// 	"G.728",
// 	"G.729",
// 	"G.711A",
// 	"G.711U",
// 	"G.726",
// 	"G.729A",
// 	"DVI4_3",
// 	"DVI4_4",
// 	"DVI4_8K",
// 	"DVI4_16K",
// 	"LPC",
// 	"S16BE_STEREO",
// 	"S16BE_MONO",
// 	"MPEGAUDIO",
// 	"LPCM",
// 	"AAC",
// 	"WMA9STD",
// 	"HEAAC",
// 	"PCM_VOICE",
// 	"PCM_AUDIO",
// 	"AACLC",
// 	"MP3",
// 	"ADPCMA",
// 	"MP4AUDIO",
// 	"AMR",

// 	pTypes[98] = "H.264"
// 	pTypes[99] = "H.265"
// 	pTypes[100] = "AVS"
// 	pTypes[101] = "SVAC"
// }

func init() {
	xproto.Register("rtp", NewRtpClient)
}

type rtpHeader struct {
	Coder              uint8
	Index              uint16
	SIM                string
	Chl                uint8
	Frame              uint8
	PktFlag            uint8
	Timestamp          uint64
	LastIFrameInterval uint16
	LastFrameInterval  uint16
	DataLength         uint16
}

// bcdSim bcd解码
func bcdSim(bcd []byte) string {
	s := ""
	for i, v := range bcd {
		if s == "" && i < 3 && bcd[i] == 0 {
			continue
		}
		s += fmt.Sprintf("%02X", v)
	}
	return s
}

type RtpClient struct {
	*xproto.Conn
	frame *xproto.Frame
}

func parseHeader(b []byte) (*rtpHeader, int) {
	h := &rtpHeader{}
	h.Coder = b[5] & 0x7f
	h.Index = binary.BigEndian.Uint16(b[6:])
	h.SIM = bcdSim(b[8:14])
	h.Chl = b[14]
	h.PktFlag = b[15] & 0x0f
	h.Frame = (b[15] >> 4) & 0x0f
	pos := 16
	if h.Frame < 0x04 { // 透传数据
		if len(b) < pos+8 {
			return h, 0
		}
		h.Timestamp = binary.BigEndian.Uint64(b[pos:])
		pos += 8
	}
	if h.Frame < 0x03 { // 非视频帧时间处理
		if len(b) < pos+4 {
			return h, 0
		}
		h.LastIFrameInterval = binary.BigEndian.Uint16(b[pos:])
		pos += 2
		h.LastFrameInterval = binary.BigEndian.Uint16(b[pos:])
		pos += 2
	}
	if len(b) < pos+2 {
		return h, 0
	}
	h.DataLength = binary.BigEndian.Uint16(b[pos:])
	pos += 2
	return h, pos
}

func isRtpValid(b []byte) (int, error) {
	l := len(b)
	if l < 18 {
		return 0, nil
	}
	if b[0] == 0x30 && b[1] == 0x31 && b[2] == 0x63 && b[3] == 0x64 {
		return l, nil
	}
	return l, errors.New("rtp header is illegal")
}

func NewRtpClient(c *xproto.Conn) xproto.IClient {
	b := c.Body()
	if _, err := isRtpValid(b); err != nil {
		return nil
	}
	c.Tag = "rtp"
	return &Client{Conn: c}
}

// callback handler; if return error not nil, will close connection
func (c *RtpClient) OnHandler(b []byte) (int, error) {
	dlen, err := isRtpValid(b)
	if err != nil || dlen == 0 {
		return 0, err
	}
	h, pos := parseHeader(b)
	nLen := pos + int(h.DataLength)
	if dlen < nLen {
		return 0, nil
	}
	// fmt.Printf("SIM %s Frame %s,%d LastFrameInterval %d\n", h.SIM, paylodType(h.PayloadType), h.Frame, h.LastFrameInterval)
	if c.frame == nil {
		c.frame = &xproto.Frame{
			DeviceNo: h.SIM,
			Channel:  uint16(h.Chl),
			Session:  fmt.Sprintf("live_%d_%s_%d", c.Port, h.SIM, h.Chl), // 这里live可以根据端口号适配成playback
		}
	}
	switch h.Frame {
	case 0x00:
		c.frame.Type = xproto.FrameVideoI
	case 0x01:
		c.frame.Type = xproto.FrameVideoP
	case 0x03:
		c.frame.Type = xproto.FrameAudio
	case 0x04:
		c.frame.Type = xproto.FrameRawData
	default:
		return nLen, nil
	}
	c.frame.Timestamp = int64(h.Timestamp)
	c.frame.Data = append(c.frame.Data, b[pos:nLen]...)
	if h.PktFlag == 0 || h.PktFlag == 0x02 { // 原子包
		c.NotifyFrame(c.frame)
		c.frame.Data = c.frame.Data[:0]
	}
	return nLen, nil
}

// idle
func (c *RtpClient) OnIdle(rt, st *time.Time) error {
	if time.Since(*st).Seconds() > 5 {
		// 要回调信令链路发送0x9105
	}
	return nil
}

// Request 发送指令
func (c *RtpClient) Request(cmd xproto.ReqCode, s interface{}, r interface{}) error {
	return nil
}
